#include "ui_manager.h"
#include "ui_slider.h"
#include "ui_verslider.h"
#include "ui_dropdown.h"
#include "ui_multiline.h"
#include "ui_progress.h"
#include "ui_checkbox.h"
// I don't need this in other platforms yet
#if defined(_PLATFORM_ANDROID) || defined(_PLATFORM_IOS)
#else
#include "ui_flashwidget.h"
#include "flash/flash_driver.h"
#endif

//#include "ui_partwidget.h"
#include "ui_part2dwidget.h"
#include "ui_mover.h"
#include "ui_replacement.h"
#include "ui_graph.h"
#include "ui_polyline.h"
#include "ui_calendar.h"
#include "ui_flexeffect.h"
#include "ui_skin.h"
#include "ui_moviewidget.h"
#include "ui_listwidget.h"
#include "ui_bipedwidget.h"
#include "ui_dragwidget.h"

#include "font/font_manager.h"
#include "console/console.h"


#include <algorithm>

#include "script/scripthelper.h"
#include "script/write_lua.h"
#include "graphics/graphics.h"
#include "graphics/graphics_util.h"


#include "util/profiler.h"		    // Needs to come in early
#include "util/timer.h"		    // Needs to come in early
#include "util/mmgr.h"		    // Needs to come in early
#include "util/common_macros.h"		// macros
#include "util/log.h"		    // logging


#ifdef _ENABLE_LUABIND
#include <luabind/luabind.hpp>
#endif // _ENABLE_LUABIND


using namespace ui;
using namespace script;
using namespace LuaPlus;


UIManager&	UIManager::Instance()
{
	static UIManager Inst;
	return Inst;
}

UIManager::UIManager() : 
	input::KeyboardListener(),
	input::MouseListener(),
	m_pFocus(NULL),
	m_pDragTarget(NULL),
	m_pEditWidget(NULL),
	m_pSelected(NULL),
	m_pTipsPanel(NULL),
	m_pCurTip(NULL),
	m_CurTipID(""),
	m_ShowCursor(false),
	m_pSelectedDropDown(NULL),
// I don't need this in other platforms yet
#if defined(_PLATFORM_ANDROID) || defined(_PLATFORM_IOS)
#else
	m_pFlashPlayer(NULL),
#endif

	m_FlashEnabled(false),
	m_pCamera(NULL),
	m_IsVisible(true),
	m_VisiblePanels(0),
	m_VisibleWidgets(0),
	m_LoadCallback(0),
	m_pLoadCBData(0)
{

	SetCursor("Cursor.png", math::Vec2(0.02f, 0.02f), math::Vec2(0.0, 0.0));
	SetDefaultFont("SmallFont");
	SetLocalization("English");
}

UIManager::~UIManager()
{
	Shutdown();
}

void				UIManager::Shutdown()
{
	DropAllPanels();
	ShutdownFlash();
}

void				UIManager::ShutdownFlash()
{
// I don't need this in other platforms yet
#if defined(_PLATFORM_ANDROID) || defined(_PLATFORM_IOS)
#else
	UTIL_SAFE_DELETE(m_pFlashPlayer);
#endif
	
}


void				UIManager::SetCursor(const std::string& File, const math::Vec2& Size, const math::Vec2& Offset)
{
#if !defined(_PLATFORM_IOS) && !defined(_PLATFORM_ANDROID)
	m_Pointer.Create(File);
	m_MouseSize = Size;
	m_MouseOffset = Offset;
#endif
}


void				UIManager::AddWidget(UIWidget* pPanel)
{
	if (PanelExists(pPanel))
		return;
	m_Panels.push_back(pPanel);
}

void				UIManager::RefreshText()
{
	for (unsigned int i=0; i<m_Panels.size(); i++)
	{
		UIWidget* pWidget = m_Panels[i];
		pWidget->RefreshText();
	}

	for (unsigned int i = 0; i < m_ExtTextObjs.size(); i++)
	{
		UIText* pText = m_ExtTextObjs[i];
		pText->RefreshText();
	}

	if (m_pTipsPanel) m_pTipsPanel->RefreshText();
}

bool				UIManager::PanelExists(UIWidget* pPanel)
{
	if (!pPanel) return false;

	for (unsigned int i=0; i<m_Panels.size(); i++)
	{
		if (m_Panels[i]==pPanel)
			return true;
	}
	return false;
}

UIWidget*			UIManager::GetPanel(const std::string& Name)
{
	for (unsigned int i=0; i<m_Panels.size(); i++)
	{
		UIWidget* pWidget = m_Panels[i];
		if (strcmpi(pWidget->GetName().c_str(), Name.c_str()) == 0)
			return pWidget;
	}
	return NULL;
}

UIWidget*	UIManager::GetWidget(const std::string& Name)
{
	for (unsigned int i=0; i<m_Panels.size(); i++)
	{
		UIWidget* pWidget = m_Panels[i];
		UIWidget* pFound = pWidget->GetWidgetByName(Name);
		if (pFound)
			return pFound;
	}
	return NULL;
}

bool				UIManager::DropWidget(UIWidget* pWidget)
{
	if (!pWidget) return false;

	if (!pWidget->GetParent())
	{
		DropPanel(pWidget);
	} else
	{
		pWidget->GetParent()->RemoveChild(pWidget, true);
	}
	return true;
}

void				UIManager::PushPanelToFront(UIWidget* pPanel)
{
	if (!pPanel) return;
	if (!PanelExists(pPanel)) return;	// no valid panel.. probably a NULL or a non-panel widget
	for (int i=0; i<(int)m_Panels.size(); i++)
	{
		if (m_Panels[i]==pPanel)
		{
			m_Panels.erase(m_Panels.begin()+i);
			m_Panels.push_back(pPanel);			// add to back of list (last panel -> front of rendering order)
			return;
		}
	}
}
void				UIManager::FlushSprites()
{
	for (int i=0; i<(int)m_Panels.size(); i++)
	{
		// flush all or non-visible only?
		m_Panels[i]->FlushSprites();
	}
}


void				UIManager::PushPanelToBack(UIWidget* pPanel)
{
	if (!pPanel) return;
	if (!PanelExists(pPanel)) return;	// no valid panel.. probably a NULL or a non-panel widget
	for (int i=0; i<(int)m_Panels.size(); i++)
	{
		if (m_Panels[i]==pPanel)
		{
			m_Panels.erase(m_Panels.begin()+i);
			m_Panels.insert(m_Panels.begin(), pPanel);		// add to front of list (back of rendering order)
			return;
		}
	}
}


void				UIManager::ResetResources()
{
	InitFlash();
	for (unsigned int i=0; i<m_Panels.size(); i++)
	{
		UIWidget* pWidget = m_Panels[i];
		pWidget->ResetResources();
	}
}

bool				UIManager::DropPanel(UIWidget* pPanel, bool Delete)
{
	for (unsigned int i=0; i<m_Panels.size(); i++)
	{
		UIWidget* pWidget = m_Panels[i];
		if (pWidget == pPanel)
		{
			if (Delete)	
				delete pWidget;
			m_Panels.erase(m_Panels.begin()+i);
			return true;
		}
	}
	return false;
}

bool				UIManager::DropAllPanels()
{
	for (unsigned int i=0; i<m_Panels.size(); i++)
	{
		UIWidget* pWidget = m_Panels[i];
		delete pWidget;
	}
	m_Panels.resize(0);

	//deleting tips panel
	UTIL_SAFE_DELETE(m_pTipsPanel);

	return true;
}


void		UIManager::Tick(float dt)
{
/// get some info from the 
	PROFILE_BLOCK("UI"); 

	if (m_pSelected && !m_pSelected->GetIsActive())
	{
		m_pSelected = NULL;
	}
	if (!m_pSelected )
	{
	
		for (int i = int(m_Panels.size())-1; i>=0; i--)
		{
			UIWidget* pWidget = m_Panels[i];
			m_pSelected = pWidget->GetTriggerWidget();
			if (m_pSelected)
				break;	// first that shows an interest
		}
	} 


/// allow all widgets to update as well
	int		Index = 0;
	for (int i = int(m_Panels.size())-1; i>=0; i--)
	{
		UIWidget* pWidget = m_Panels[i];
		pWidget->Tick(dt);
	}

	//tick tips
	TickTips(dt);

	if (m_pDragTarget)
		FontManager::Instance().Print(math::Vec2(0.2f, 0.2f), "%.2f, %.2f", m_DragFrom.x, m_DragFrom.y);

}



void UIManager::TickTips(float dt)
{

	if (m_pCurTip != NULL)
	{
		m_TipCounter.Tick(dt);

		if (m_TipCounter.IsReady() == true)
		{
			m_pCurTip->SetIsVisible(true);
			
			math::Vec2 CursorSize(32.0f / (float)GraphicsUtil::WIDTH, 32.0f / (float)GraphicsUtil::HEIGHT);
			math::Vec2 CurTipPos = m_MousePos + CursorSize;
			m_pCurTip->ResizeToText();
			math::Vec2 CurTipSize= m_pCurTip->GetSize();

			//additional reposition

			if (CurTipPos.x + CurTipSize.x > 1.0f)
				CurTipPos.x = m_MousePos.x - CurTipSize.x - CursorSize.y;

			if (CurTipPos.y + CurTipSize.y > 1.0f)
				CurTipPos.y = m_MousePos.y - CurTipSize.y - CursorSize.y; 

			if (CurTipPos.x < 0.0f)
				CurTipPos.x = 0.0f;

			if (CurTipPos.y < 0.0f)
				CurTipPos.y = 0.0f;

			m_pCurTip->SetPosition(CurTipPos);

		}
	}

	if (m_pTipsPanel != NULL)
	{
		m_pTipsPanel->Tick(dt);
	}

}



void		UIManager::Render()
{	
	if (!m_IsVisible) return;
	m_VisiblePanels = 0;
	m_VisibleWidgets = 0;
	PROFILE_BLOCK("UI");
	math::Vec2	BasePos;
	for (unsigned int i = 0; i<m_Panels.size(); i++)
	{
		UIWidget* pWidget = m_Panels[i];
		if (pWidget->IsVisible())
		{
			// TODO: Check for screenspace visibility as well?
			pWidget->Render();
			pWidget->PostRender();
			m_VisiblePanels++;
		}
	}
/*
	//	Uncomment this for a quick overview of what panels are visible at any time.
	int Count = 0;
	for (unsigned int i = 0; i<m_Panels.size(); i++)
	{
		UIWidget* pWidget = m_Panels[i];
		if (pWidget->IsVisible())
		{
			Count++;
			BasePos.y+=0.01f;
			FontManager::Instance().Print(BasePos, "Panel Name = %s", pWidget->GetName().c_str());
		}
	}
	FontManager::Instance().Print(math::Vec2(0, 0.5), "PanelC = %i", Count);
*/
	//RENDERING TIPS
	if (m_pTipsPanel != NULL)
	{
		m_pTipsPanel->Render();
		m_pTipsPanel->PostRender();
	}

	if (m_pDragTarget)
		m_pDragTarget->Render(true);


//	for (std::list<UIWidget*>::iterator It = m_Panels.begin(); It != m_Panels.end(); It++)
//		(*It)->PostRender();

	if (m_ShowCursor)
	{
		m_Pointer.Setup(m_MousePos+m_MouseOffset, m_MouseSize);
		m_Pointer.Render();
	}
}
bool		UIManager::HasActiveAnimation()
{
	for (unsigned int i = 0; i<m_Panels.size(); i++)
		if (m_Panels[i]->HasAnimation()) return true;
	return false;	
}

UIWidget*	UIManager::AddEmptyPanel(const std::string& Name)
{
	UIWidget* pWidget = new UIWidget(NULL, Name);
	AddWidget(pWidget);
	return pWidget;
}

void		UIManager::SavePanel(UIWidget* pPanel, const std::string& File)
{
	if (!pPanel) return;
	script::WriteLua	WL;

	WL.Open(File);
	WL.StartTable("Panel");
		pPanel->ExportToFile(&WL);

	WL.CloseTable(false);
}

UIWidget*	UIManager::AddPanel(const std::string& File)
{
	UpdateLoadCB();
	if (File.empty())
	{
		_LOG(MSG_ERROR, "Unable to load empty UI file!");
		return NULL;
	}
	UIWidget*	pWidget = NULL;
	LuaPlus::LuaState*	pScript = ScriptHelper::CreateLuaState();
	if (!ScriptHelper::DoFile(*pScript, File))
	{
		_LOG(MSG_ERROR, "Unable to load UI panel " << File << "!");
		 LuaState::Destroy( pScript );
		return NULL;
	} else
	{
		LuaPlus::LuaObject	Panel = ScriptHelper::GetObj(*pScript, "Panel");
		if (Panel.IsTable())
		{
			const std::string Name = ScriptHelper::GetTableString(Panel, "Name");

			if (Name == "_TipsPanel") //FOR TIPS PANEL
			{
				if (m_pTipsPanel != NULL)
					UTIL_SAFE_DELETE(m_pTipsPanel);

				m_pTipsPanel = CreateWidget(NULL, Panel);
				m_pTipsPanel->SetFile(File);

				_LOG(MSG_LOAD, "TIPS panel loaded from file " << File);

				//initial hide of all the children
				std::vector<UIWidget*> TipsVector;
				m_pTipsPanel->GetChildren(TipsVector);
				for (int i = 0; i < (int)TipsVector.size(); i++)
					TipsVector.at(i)->SetIsVisible(false);
			} 
			else //FOR ALL OTHER PANELS
			{

				UIWidget* pExists = GetPanel(Name);
				if (pExists) 
				{
					// force a reload?
					pWidget = pExists;
				} else
				{
					pWidget = CreateWidget(NULL, Panel);
					if (pWidget)
					{
						AddWidget(pWidget);
						pWidget->PostLoad();
						_LOG(MSG_LOAD, "UI panel " << pWidget->GetName() << " loaded from file " << File);
						pWidget->SetFile(File);
					}
				}
			}
		} else
		{
			_LOG(MSG_ERROR, "Unable to load UI panel " << File << "!");
		}
	}
	// IMPORTANT: CANNOT DESTROY BEFORE WE'RE OUT OF THAT IF STATEMENT!
	LuaState::Destroy( pScript );
	return pWidget;
}


UIWidget*	UIManager::CreateWidget(UIWidget* pParent, const std::string& WidgetType)
{

	std::string	Type = WidgetType;
	std::transform(Type.begin(), Type.end(), Type.begin(), tolower);

	UIWidget*	pWidget = NULL;


	if (Type == "widget")	pWidget = new UIWidget(pParent); else
	if (Type == "slider")	pWidget = new UISlider(pParent); else
	if (Type == "verslider")pWidget = new UIVerSlider(pParent); else
	if (Type == "progress") pWidget = new UIProgress(pParent); else
	if (Type == "dropdown") pWidget = new UIDropDown(pParent); else
	if (Type == "checkbox") pWidget = new UICheckBox(pParent); else
#ifndef _PLATFORM_WII
	//if (Type == "flash")	pWidget = new UIFlashWidget(pParent); else
#endif
	if (Type == "part2d")	pWidget = new UIPart2DWidget(pParent); else
	if (Type == "multiline") pWidget = new UIMultiLine(pParent); else
	if (Type == "graph")	pWidget = new UIGraph(pParent); else
	if (Type == "polyline") pWidget = new UIPolyLine(pParent); else
	if (Type == "movie")	pWidget = new UIMovieWidget(pParent); else	
	if (Type == "calendar")	pWidget = new UICalendar(pParent); else	
	if (Type == "flexeffect") pWidget = new UIFlexEffect(pParent); else
	if (Type == "list")		pWidget = new UIListWidget(pParent); else
	if (Type == "biped")	pWidget = new UIBipedWidget(pParent); else
	if (Type == "drag")		pWidget = new UIDragWidget(pParent); else
							pWidget = new UIWidget(pParent);

	return pWidget;
}

UIWidget*	UIManager::CreateWidget(UIWidget* pParent, LuaPlus::LuaObject  _LObj)
{
	if (!_LObj.IsTable())
		return NULL;
	std::string	Type = ScriptHelper::GetTableString(_LObj, "Type", "Widget");
	UIWidget*	pWidget = CreateWidget(pParent, Type);
	if (pWidget)
	{
		if (!pWidget->Load(_LObj))
		{

			UTIL_SAFE_DELETE(pWidget);
		}
	}

	return pWidget;
}

void		UIManager::ExecuteScript(const std::string& Script)
{
	// we borrow the console's state for now
	console::Console::Instance().Do(Script);
}

struct	RefreshEntry
{
	std::string		PanelFile;
	UIWidget*		pWidget;
};

void		UIManager::RefreshFonts()
{
	for (unsigned int i = 0; i<m_Panels.size(); i++)
	{
		UIWidget* pWidget = m_Panels[i];
		pWidget->RefreshFonts();

	}

	for (unsigned int i = 0; i < m_ExtTextObjs.size(); i++)
	{
		m_ExtTextObjs[i]->SetFont( m_ExtTextObjs[i]->GetFontName() );
	}

	if (m_pTipsPanel) m_pTipsPanel->RefreshFonts();
}

void		UIManager::RefreshActive()
{
	std::vector<RefreshEntry>	ToRefresh;
	for (unsigned int i = 0; i<m_Panels.size(); i++)
	{
		UIWidget* pWidget = m_Panels[i];
		if (pWidget->IsVisible())
		{
			RefreshEntry	Entry;
			Entry.PanelFile = pWidget->GetFile();
			Entry.pWidget = pWidget;
			ToRefresh.push_back(Entry);
		}
	}
	for (unsigned int i=0; i<ToRefresh.size(); i++)
	{
		DropPanel(ToRefresh[i].pWidget, true);
	}

	for (unsigned int i=0; i<ToRefresh.size(); i++)
	{
		AddPanel(ToRefresh[i].PanelFile);
	}
}

bool		UIManager::MouseInsideActive(const math::Vec2& Pos)
{
	if (!m_IsVisible) return false;
	for (int i = int(m_Panels.size())-1; i>=0; i--)
	{
		UIWidget* pWidget = m_Panels[i];
		if (!pWidget->IsActive()) continue;
		if (pWidget->CursorInsideActiveWidget(Pos)) 
			return true;
	}
	return false;
}

bool		UIManager::MouseInside(const math::Vec2& Pos)
{
	if (!m_IsVisible) return false;
	for (int i = int(m_Panels.size())-1; i>=0; i--)
	{
		UIWidget* pWidget = m_Panels[i];
		if (!pWidget->IsActive()) continue;		// only works on active widgets
		if (pWidget->CursorInsideWidget(Pos)) 
			return true;
	}
	return false;
}

/////////////////////////////////////////////////////////////////////////
// events
void		UIManager::EnableInput(bool b)
{
	if (b)
	{
		input::KeyboardListener::Enable();
		input::MouseListener::Enable();
	} else
	{
		input::KeyboardListener::Disable();
		input::MouseListener::Disable();
	}
}

void		UIManager::MouseButtonPressed(input::Mouse::BUTTON_STATE* pKey, const math::Vec2& Pos)
{
	if (!m_IsVisible) return;
	if (m_pSelectedDropDown && !m_pSelectedDropDown->IsInside(Pos) && m_pSelectedDropDown->IsOpen())
	{
		m_pSelectedDropDown->SetOpen(false);
		m_pSelectedDropDown = NULL;
		return;
	}
	if (m_pSelectedDropDown && m_pSelectedDropDown->IsInside(Pos))
	{
		m_pSelectedDropDown->OnMousePress(Pos, pKey->ButtonID);
		return;
	}

	if (m_pEditWidget && m_pEditWidget->IsInside(Pos))
	{
		m_pEditWidget->PutCursor(Pos);
	} else
	{
		for (int i = int(m_Panels.size())-1; i>=0; i--)
		{
			UIWidget* pWidget = m_Panels[i];
			/// consumed by the panel ?
			if (pWidget->OnMousePress(Pos, pKey->ButtonID)) return;
		}
	}
}

void		UIManager::MouseButtonReleased(input::Mouse::BUTTON_STATE* pKey, const math::Vec2& Pos)
{
	if (!m_IsVisible) return;
	if (m_pSelectedDropDown && m_pSelectedDropDown->IsInside(Pos))
	{
		m_pSelectedDropDown->OnMouseRelease(Pos, pKey->ButtonID);
		return;
	}
/*	for (int i = int(m_Panels.size())-1; i>=0; i--)
	{
		UIWidget* pWidget = m_Panels[i];
		m_pSelected = pWidget->GetWidgetAtPos(Pos);
		if (m_pSelected) break;
	}*/
	for (int i = int(m_Panels.size())-1; i>=0; i--)
	{
		UIWidget* pWidget = m_Panels[i];
		if (pWidget->OnMouseRelease(Pos, pKey->ButtonID)) return;
	}
}

void		UIManager::MouseButtonDown(input::Mouse::BUTTON_STATE* pKey, const math::Vec2& Pos)
{
	//removing tip
	if (m_pCurTip != NULL)
	{
		m_pCurTip->SetIsVisible(false);
		m_pCurTip = NULL;
		m_CurTipID = "";
	}

	if (m_pSelectedDropDown && m_pSelectedDropDown->IsInside(Pos))
	{
		m_pSelectedDropDown->OnMouseDown(Pos, pKey->ButtonID);
		return;
	}
	for (int i = int(m_Panels.size())-1; i>=0; i--)
	{
		UIWidget* pWidget = m_Panels[i];
		if (pWidget->OnMouseDown(Pos, pKey->ButtonID)) return;
	}
}


void		UIManager::MouseButtonRepeat(input::Mouse::BUTTON_STATE* pKey, const math::Vec2& Pos)
{
	if (!m_IsVisible) return;
	if (m_pSelectedDropDown && m_pSelectedDropDown->IsInside(Pos))
	{
		m_pSelectedDropDown->OnMouseRepeat(Pos, pKey->ButtonID);
		return;
	}
	for (int i = int(m_Panels.size())-1; i>=0; i--)
	{
		UIWidget* pWidget = m_Panels[i];
		if (pWidget->OnMouseRepeat(Pos, pKey->ButtonID)) return;
		// (*It)->OnMouseDown(Pos, pKey->ButtonID);
	}
}

void		UIManager::MouseButtonDblClick(input::Mouse::BUTTON_STATE* pKey, const math::Vec2& Pos)
{
	if (m_pSelectedDropDown && m_pSelectedDropDown->IsInside(Pos))
	{
		m_pSelectedDropDown->OnMouseDblClick(Pos, pKey->ButtonID);
		return;
	}
	if (m_pEditWidget && m_pEditWidget->IsInside(Pos))
	{
		m_pEditWidget->SelectAll();
	} else
	{
		for (int i = int(m_Panels.size())-1; i>=0; i--)
		{
			UIWidget* pWidget = m_Panels[i];
			if (pWidget->OnMouseDblClick(Pos, pKey->ButtonID)) return;
		}
	}
}


void		UIManager::MouseWheelMove(int WheelInfo, const math::Vec2& Pos)
{
	if (!m_IsVisible) return;
	// not really interested in mouse-wheel yet
}

void		UIManager::MouseHoover(const math::Vec2& Pos)
{
	if (!m_IsVisible) return;
	for (int i = int(m_Panels.size())-1; i>=0; i--)
	{
		UIWidget* pWidget = m_Panels[i];
		/// consumed by the panel ?
		pWidget->OnMouseHoover(Pos);
	}
}

void		UIManager::UpdateLocalization()
{
	for (int i = int(m_Panels.size())-1; i>=0; i--)
	{
		UIWidget* pWidget = m_Panels[i];
		/// consumed by the panel ?
		pWidget->UpdateLocalization();
	}

	if (m_pTipsPanel) m_pTipsPanel->UpdateLocalization();
}

void		UIManager::MouseMove(const math::Vec2& From, const math::Vec2& To)
{
	if (!m_IsVisible) return;
	if (m_pSelectedDropDown && m_pSelectedDropDown->IsInside(To))
	{
		m_pSelectedDropDown->OnMouseMove(From, To);
		return;
	}
	m_MousePos = To;
	for (int i = int(m_Panels.size())-1; i>=0; i--)
	{
		UIWidget* pWidget = m_Panels[i];
		if (pWidget->GetIsVisible()) 
		{
			/// consumed by the panel ?
			pWidget->OnMouseMove(From, To);
			if (pWidget->BlocksAllEvents() && pWidget->IsInside(To))
				break;
		}
	}

	// process any mouse off
	for (int i = int(m_Panels.size())-1; i>=0; i--)
	{
		UIWidget* pWidget = m_Panels[i];

		if (pWidget->GetIsVisible()) 
		{
			pWidget->ProcessMouseOff();
			if (pWidget->BlocksAllEvents() && pWidget->IsInside(To))
				break;
		}
	}

	//resetting cur tip
	if (m_pCurTip != NULL)
	{
		//hiding all other tips
		std::vector<UIWidget*> TipsVector;
		m_pTipsPanel->GetChildren(TipsVector);

		for (int i = 0; i < (int)TipsVector.size(); i++)
		{
			if (TipsVector.at(i) != m_pCurTip)
				TipsVector.at(i)->SetIsVisible(false);
		}
	}

	UIWidget* pOldTip = m_pCurTip;
	m_CurTipID = "";
	m_pCurTip = NULL;

	// process any mouse over
	for (int i = int(m_Panels.size())-1; i>=0; i--)
	{
		UIWidget* pWidget = m_Panels[i];
		if (pWidget->GetIsVisible())
		{
			pWidget->ProcessMouseOver();
			if (pWidget->BlocksAllEvents() && pWidget->IsInside(To))
				break;
		}
	}

	//getting new cur tip
	
	if (m_pTipsPanel != NULL && m_CurTipID != "")
		m_pCurTip = m_pTipsPanel->GetWidgetByName(m_CurTipID);

	if (m_pCurTip != NULL)
	{
		m_TipCounter.SetLimit(((float)TIPDELAY) * 0.001f);
		//hiding all other tips
		std::vector<UIWidget*> TipsVector;
		m_pTipsPanel->GetChildren(TipsVector);

		for (int i = 0; i < (int)TipsVector.size(); i++)
		{
			if (pOldTip == m_pCurTip && m_pCurTip != TipsVector.at(i))
				TipsVector.at(i)->SetIsVisible(false);
		}

		if (pOldTip == m_pCurTip)
			m_pCurTip->SetIsVisible(true);
		else
		{
			_LOG(MSG_COMMENT, "TIP: new tip set. Name = " << m_pCurTip->GetName());
			_LOG(MSG_COMMENT, "TIP: m_CurTipID = " << m_CurTipID);
			if (m_pTipsPanel == NULL)
				_LOG(MSG_COMMENT, "TIP: panel is null!");
			else
			{
				_LOG(MSG_COMMENT, "TIP: tips panel children count = " << m_pTipsPanel->GetElementC());  
				_LOG(MSG_COMMENT, "TIP: tips panel name = " << m_pTipsPanel->GetName());
			}
		}
	}

	if (pOldTip != NULL && m_pCurTip == NULL)
		pOldTip->SetIsVisible(false);

	if (pOldTip != NULL && m_pCurTip != pOldTip)
		pOldTip->SetIsVisible(false);
}

void		UIManager::MouseOnDrag(const math::Vec2& From, const math::Vec2& To)
{
	if (!m_IsVisible) return;

	if (m_pEditWidget && m_pEditWidget->IsInside(From))
	{
		m_pEditWidget->SelectRegion(From, To);
	} else
	{
		// see if someone else has priority
		if (m_pDragTarget)
		{
			m_pDragTarget->OnMouseDrag(From, To);
			return;
		}
		for (int i = int(m_Panels.size())-1; i>=0; i--)
		{
			UIWidget* pWidget = m_Panels[i];
			// stop on the first valid one
			if (pWidget->OnMouseDrag(From, To))
				return;
		}
	}
}

void		UIManager::SetDragTarget(UIWidget* pWidget)
{ 
	if (!m_pDragTarget || m_pDragTarget != pWidget)
	{
		m_pDragTarget = pWidget; 
		if (m_pDragTarget)
		{
			m_DragFrom = m_pDragTarget->GetPosition();
		} 
	}
}

void		UIManager::MouseOnDrop(const math::Vec2& From, const math::Vec2& To)
{
	if (!m_IsVisible) return;
	for (int i = int(m_Panels.size())-1; i>=0; i--)
	{
		UIWidget* pWidget = m_Panels[i];
		pWidget->OnMouseDrop(From, To, m_pDragTarget);
	}

	if (m_pDragTarget)
	{
		// if it doesn't care itself, return it to whence it came
		if (!m_pDragTarget->TriggerEvent(UIWidget::WE_DROP))
		{
			if (m_pDragTarget->GetParent())
				m_pDragTarget->SetPosition(m_DragFrom - m_pDragTarget->GetParent()->GetPosition());
			else
				m_pDragTarget->SetPosition(m_DragFrom);
		}
		m_pDragTarget = NULL;	// no longer used
	}
}

void		UIManager::CharReceived(unsigned int Key)
{
	if (!m_IsVisible) return;
	if (m_pEditWidget && m_pEditWidget->m_pOwner && m_pEditWidget->m_pOwner->IsParentVisible() && !m_pEditWidget->m_pOwner->IsMoving())
		m_pEditWidget->CharReceived(Key);
}


void		UIManager::KeyPressed(input::Keyboard::KEY* pKey)
{
	if (!m_IsVisible) return;
	if (m_pEditWidget && m_pEditWidget->m_pOwner && m_pEditWidget->m_pOwner->IsParentVisible() && !m_pEditWidget->m_pOwner->IsMoving())
		m_pEditWidget->KeyPressed(pKey);
}

void		UIManager::KeyRepeat(input::Keyboard::KEY* pKey)
{
	if (!m_IsVisible) return;
	if (m_pEditWidget && m_pEditWidget->m_pOwner && m_pEditWidget->m_pOwner->IsParentVisible() && !m_pEditWidget->m_pOwner->IsMoving())
		m_pEditWidget->KeyPressed(pKey);
}

void		UIManager::KeyReleased(input::Keyboard::KEY* pKey)
{
	if (!m_IsVisible) return;
	UIWidget::WIDGET_EVENT	Event = UIWidget::WE_UNKNOWN;
	switch (pKey->KeyID)
	{
		case KEY_UP:			Event = UIWidget::WE_UP_KEY; break;
		case KEY_DOWN:			Event = UIWidget::WE_DOWN_KEY; break;
		case KEY_TAB:			Event = UIWidget::WE_TAB_KEY; break;
		default:
			return;	// do nothing
	}
	if (m_pEditWidget && m_pEditWidget->m_pOwner && m_pEditWidget->m_pOwner->IsParentVisible() && !m_pEditWidget->m_pOwner->IsMoving())
	{
		if (m_pEditWidget->m_pOwner && Event != UIWidget::WE_UNKNOWN)
		{
			m_pEditWidget->m_pOwner->TriggerEvent(Event);
		}
		return;
	}
	Event = UIWidget::WE_UNKNOWN;
	switch (pKey->KeyID)
	{
		case KEY_LEFT:			Event = UIWidget::WE_LEFT_KEY; break;
		case KEY_RIGHT:			Event = UIWidget::WE_RIGHT_KEY; break;
		case KEY_RETURN:		Event = UIWidget::WE_TEXT_ENTER; break;
		default:
			return;	// do nothing
	}
	if (Event != UIWidget::WE_UNKNOWN)
	{
		for (int i = int(m_Panels.size())-1; i>=0; i--)
		{
			UIWidget* pWidget = m_Panels[i];
			if (pWidget->IsActive() && pWidget->TriggerEvent(Event))
			{
				return;	// first that shows an interest
			}
		}
	}
}

void		UIManager::KeyDown(input::Keyboard::KEY* pKey)
{

}

void		UIManager::SetFocus(UIWidget* pWidget)
{
	if (m_pFocus != pWidget)
	{
		m_pEditWidget = NULL;
		m_pFocus = pWidget;
	}
}

void		UIManager::SetEditWidget(UIWidget* pWidget)
{
	if (pWidget && pWidget->GetTextObj()->IsEditable())
	{
		m_pFocus = pWidget;
		m_pDragTarget = NULL;
		m_pEditWidget = pWidget->GetTextObj();
		m_pEditWidget->SelectAll();
	} else
	{
		m_pFocus = NULL;
		m_pDragTarget = NULL;
		m_pEditWidget = NULL;
	}
}

void	UIManager::ClearEditWidget()
{
	SetEditWidget(NULL);
}

void	UIManager::ForceLeftAlign(bool b)
{
	UIText::ForceLeftAlign(b);
}

void	UIManager::InitFlash()
{
// I don't need this in other platforms yet
#if defined(_PLATFORM_ANDROID) || defined(_PLATFORM_IOS) 
#else
	if (!m_pFlashPlayer && m_FlashEnabled)
	{
		m_pFlashPlayer = new flash::FlashDriver();
		m_pFlashPlayer->Init();
	}
#endif


}

void	UIManager::AddReplaceWord(const std::string& From, const std::string& To)
{
	UIReplacement::Instance().SetReplacement(From, To);
}

void	UIManager::RegisterExternalText(UIText* pTextObj)
{
	for (int i = 0; i < (int)m_ExtTextObjs.size(); i++)
	{
		if (pTextObj == m_ExtTextObjs[i])
			return; // already exists
	}

	m_ExtTextObjs.push_back(pTextObj);
}

void	UIManager::DeRegisterExternalText(UIText* pTextObj)
{
	for (int i = 0; i < (int)m_ExtTextObjs.size(); i++)
	{
		if (pTextObj == m_ExtTextObjs[i])
		{
			m_ExtTextObjs.erase(m_ExtTextObjs.begin() + i);
			return;
		}
	}
}



void UIManager::Register(LuaPlus::LuaState* _pScript)
{
#ifdef _ENABLE_LUABIND
	UIWidget::Register(_pScript);
	UIProgress::Register(_pScript);
	UISlider::Register(_pScript);
	UIVerSlider::Register(_pScript);
	UIDropDown::Register(_pScript);
	UICheckBox::Register(_pScript);
	UIMultiLine::Register(_pScript);
	UIFlashWidget::Register(_pScript);
	UIMovieWidget::Register(_pScript);
	UIPart2DWidget::Register(_pScript);
	UIGraph::Register(_pScript);
	UIListWidget::Register(_pScript);
	UIBipedWidget::Register(_pScript);

	UIMover::Register(_pScript);
    lua_State * L = _pScript->GetCState ( );

	luabind::module(L)
    [

		luabind::class_< UIManager>( "UIManager" )
		.def( "AddPanel",			&UIManager::AddPanel)
        .def( "GetWidget",			&UIManager::GetWidget)
        .def( "GetPanel",			&UIManager::GetPanel)
        .def( "GetFocus",			&UIManager::GetFocus)
        .def( "SetFocus",			&UIManager::SetFocus)
		.def( "SetEditWidget",		&UIManager::SetEditWidget)
        .def( "GetDragTarget",		&UIManager::GetDragTarget)
        .def( "ExecuteScript",		&UIManager::ExecuteScript)
		.def( "SavePanel",			&UIManager::SavePanel)		
		.def( "PushPanelToFront",	&UIManager::PushPanelToFront)
		.def( "PushPanelToBack",	&UIManager::PushPanelToBack)
		.def( "RefreshActive",		&UIManager::RefreshActive)
		.def( "ClearEditWidget",	&UIManager::ClearEditWidget)
		.def( "ForceLeftAlign",		&UIManager::ForceLeftAlign)
		.def( "AddReplaceWord",		&UIManager::AddReplaceWord)
		.def( "HasActiveAnimation",	&UIManager::HasActiveAnimation)
		.def( "EnableInput",		&UIManager::EnableInput)
	];
	
	luabind::module(L)
    [	luabind::def( "GetUIMan",     &UIManager::Instance )	];

	
#endif // _ENABLE_LUABIND
}

